#pragma once

#include "corebase_global.h"
#include <osg/Matrix>
#include <osg/Vec3>
#include <osg/Vec4>

namespace CoreBase
{
	class COREBASE_EXPORT Transform
	{
	public:

		Transform(float tx = 0.0f, float ty = 0.0f, float tz = 0.0f,
			float h = 0.0f, float p = 0.0f, float r = 0.0f);
		Transform(const Transform& that);
		virtual ~Transform();
		bool isIdentity() const 
		{ 
			return _ransform.isIdentity();
		}
		void makeIdentity() 
		{
			_ransform.makeIdentity();
		}
		void makeScale(const osg::Vec3d& scalevec) 
		{ 
			_ransform.makeScale(scalevec);
		}
		void makeScale(const osg::Vec3f& scalevec)
		{ 
			_ransform.makeScale(scalevec); 
		}
		void makeScale(osg::Matrix::value_type x, osg::Matrix::value_type y, osg::Matrix::value_type z)
		{ 
			_ransform.makeScale(x,y,z);
		}
		void getRow(unsigned index, osg::Vec3& row) const;
		void setRow(unsigned index, const osg::Vec3& row);
		void getRow(unsigned index, osg::Vec4& row) const;
		void setRow(unsigned index, const osg::Vec4& row);
		virtual void set(float tx, float ty, float tz,
			float h, float p, float r);
		virtual void set(const osg::Vec3& xyz, const osg::Vec3& hprrotation);
		virtual void set(const osg::Vec3& xyz, const osg::Quat& quat);
		virtual void set(const osg::Vec3& xyz, const osg::Matrix& rotation);
		virtual void set(const osg::Matrix& mat);
		void set(const osg::Vec3& xyz, const osg::Vec3& lookatxyz, const osg::Vec3& upvec);
		void set(float posx, float posy, float posz,
			float lookatx, float lookaty, float lookatz,
			float upvecx, float upvecy, float upvecz);
		virtual void setTranslation(float tx, float ty, float tz) 
		{
			setTranslation(osg::Vec3(tx, ty, tz));
		}
		virtual void setTranslation(const osg::Vec3f& xyz) 
		{ 
			_ransform.setTrans( xyz );
		}
		virtual void setTranslation(const osg::Vec3d& xyz) 
		{
			_ransform.setTrans( xyz ); 
		}
		void move(const osg::Vec3f& distance);
		void move(const osg::Vec3d& distance);
		virtual void setRotation(float h, float p, float r)
		{ 
			setRotation(osg::Vec3(h, p, r));
		}
		virtual void setRotation(const osg::Vec3& hpr);
		virtual void setRotation(const osg::Quat& quat) 
		{
			_ransform.setRotate(quat);
		}
		virtual void setRotation(const osg::Matrix& rotation);
		void get(float& tx, float& ty, float& tz, float& h, float& p, float& r) const;
		void get(osg::Vec3& xyz, osg::Matrix& rotation) const;
		void get(osg::Vec3& xyz, osg::Vec3& hpr) const;
		void get(osg::Vec3& xyz, osg::Quat& quat) const;
		void get(osg::Matrix& matrix) const;
		void getTranslation(osg::Vec3f& translation) const 
		{
			translation.set(_ransform.getTrans());
		}
		void GetTranslation(osg::Vec3d& translation) const 
		{
			translation.set(_ransform.getTrans());
		}
		void getTranslation(float& tx, float& ty, float& tz) const;
		const osg::Vec3 GetTranslation() const 
		{ 
			return _ransform.getTrans(); 
		}
		void getRotation(float& h, float& p, float& r) const;
		void getRotation(osg::Vec3& hpr) const;
		void getRotation(osg::Quat& quat) const 
		{
			quat = _ransform.getRotate(); 
		}
		void getRotation(osg::Matrix& rotation) const;
		osg::Vec3 getRotation() const 
		{ 
			osg::Vec3 hpr; 
			getRotation(hpr); 
			return hpr; 
		}
		void getOrientation(osg::Vec3& right, osg::Vec3& up, osg::Vec3& forward);
		void calcScale(osg::Vec3f& scale) const;
		void calcScale(osg::Vec3d& scale) const;
		double calcDistance(const Transform& xform);
		double calcDistanceSquared(const Transform& xform);
		void rescale(const osg::Vec3d& scale);
		void rescale(const osg::Vec3f& scale);
		bool epsilonEquals(const Transform& transform, float epsilon = 0.0001f) const;
		bool isValid() const 
		{
			return _ransform.valid();
		};
		osg::Matrix::value_type& operator()(unsigned i, unsigned j) { return _ransform(i, j); }
		osg::Matrix::value_type operator()(unsigned i, unsigned j) const { return _ransform(i, j); }
		Transform & operator=(const Transform &);
		bool        operator==(const Transform &);
	private:
		osg::Matrix _ransform;
	};
}